package com.alibaba.chaosblade.box.service.impl;

import com.alibaba.chaosblade.box.common.commands.CommandBus;
import com.alibaba.chaosblade.box.common.common.domain.Response;
import com.alibaba.chaosblade.box.common.common.domain.experiment.ExperimentRunResult;
import com.alibaba.chaosblade.box.common.common.domain.user.ChaosUser;
import com.alibaba.chaosblade.box.common.infrastructure.constant.ChangelogTypes;
import com.alibaba.chaosblade.box.common.infrastructure.constant.ChangelogTypes.*;
import com.alibaba.chaosblade.box.common.infrastructure.domain.experiment.flow.ExperimentActivityInfo;
import com.alibaba.chaosblade.box.common.infrastructure.domain.experiment.request.*;
import com.alibaba.chaosblade.box.common.infrastructure.domain.experiment.response.ExperimentInit;
import com.alibaba.chaosblade.box.common.infrastructure.exception.ChaosException;
import com.alibaba.chaosblade.box.dao.command.ExperimentExecutionCommand;
import com.alibaba.chaosblade.box.dao.infrastructure.monitor.trace.Trackers;
import com.alibaba.chaosblade.box.common.infrastructure.util.ChangeLogExecutor;
import com.alibaba.chaosblade.box.dao.infrastructure.experiment.request.ExperimentCreateRequest;
import com.alibaba.chaosblade.box.dao.infrastructure.experiment.request.ExperimentDefinitionRequest;
import com.alibaba.chaosblade.box.dao.infrastructure.experiment.request.ExperimentUpdateRequest;
import com.alibaba.chaosblade.box.service.ExperimentWriteService;
import com.alibaba.chaosblade.box.service.command.experiment.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * @author haibin.lhb
 */
@Service
public class ExperimentWriteServiceImpl implements ExperimentWriteService {

    @Autowired
    private CommandBus commandBus;

    @Autowired
    private Trackers trackers;

    /**
     * 运行演练
     *
     * @param user                 用户信息
     * @param experimentRunRequest 运行演练的请求
     * @return 运行结果
     * @throws ChaosException 异常信息
     */
    @Override
    public Response<ExperimentRunResult> runExperiment(ChaosUser user, ExperimentRunRequest experimentRunRequest)
            throws ChaosException {

        // 执行演练运行命令，并在成功后记录操作日志
        return ChangeLogExecutor.executeWithChangeLog(
                // 同步执行演练运行命令，传入用户请求参数
                () -> commandBus.syncRun(ExperimentExecutionCommand.class, experimentRunRequest),
                // 命令执行成功后的回调处理
                experimentRunResultResponse -> {
                    if (experimentRunResultResponse.isSuccess()) {
                        // 记录演练任务运行操作日志
                        trackers.trackExperimentTaskOperation(
                                ChangeActionType.RUN,           // 操作类型：运行
                                ChangeOperatorType.USER,        // 操作者类型：用户
                                user,                           // 当前用户
                                experimentRunRequest.getExperimentId(),  // 演练ID
                                experimentRunResultResponse.getResult().getTaskId()  // 生成的演练任务ID
                        );
                    }
                });
    }

    /**
     * 创建演练
     *
     * @param experimentCreateRequest 创建演练的请求
     * @return 创建结果
     * @throws ChaosException 异常信息
     */
    @Override
    public Response<String> createExperiment(ExperimentCreateRequest experimentCreateRequest)
            throws ChaosException {
        return ChangeLogExecutor.executeWithChangeLog(
                () -> commandBus.syncRun(ExperimentCreateCommand.class, experimentCreateRequest),
                experimentRunResultResponse -> {
                    if (experimentRunResultResponse.isSuccess()) {
                        trackers.trackExperimentOperation(ChangeActionType.ADD, ChangeOperatorType.USER,
                                experimentCreateRequest.getUser(),
                                experimentRunResultResponse.getResult(), null);
                    }
                });
    }

    /**
     * 更新演练
     *
     * @param experimentUpdateRequest 更新演练的请求
     * @return 更新结果
     * @throws ChaosException 异常信息
     */
    @Override
    public Response<Boolean> updateExperiment(ExperimentUpdateRequest experimentUpdateRequest)
            throws ChaosException {
        return ChangeLogExecutor.executeWithChangeLog(
                () -> commandBus.syncRun(ExperimentUpdateCommand.class, experimentUpdateRequest),
                experimentRunResultResponse -> {
                    if (experimentRunResultResponse.isSuccess()) {
                        trackers.trackExperimentOperation(ChangelogTypes.ChangeActionType.Update, ChangeOperatorType.USER,
                                experimentUpdateRequest.getUser(),
                                experimentUpdateRequest.getExperimentId(), null);
                    }
                });
    }

    /**
     * 更新演练基本信息
     *
     * @param user                    用户信息
     * @param experimentUpdateRequest 更新演练基本信息的请求
     * @return 更新结果
     * @throws ChaosException 异常信息
     */
    @Override
    public Response<Boolean> updateExperimentBasicInfo(ChaosUser user, ExperimentUpdateRequest experimentUpdateRequest)
            throws ChaosException {
        return ChangeLogExecutor.executeWithChangeLog(
                () -> commandBus.syncRun(ExperimentUpdateCommand.class, experimentUpdateRequest),
                experimentRunResultResponse -> {
                    if (experimentRunResultResponse.isSuccess()) {
                        trackers.trackExperimentOperation(ChangeActionType.Update, ChangeOperatorType.USER,
                                experimentUpdateRequest.getUser(),
                                experimentUpdateRequest.getExperimentId(), null);
                    }
                });
    }

    /**
     * 克隆演练
     *
     * @param experimentCloneRequest 克隆演练的请求
     * @return 克隆结果
     */
    @Override
    public Response<String> cloneExperiment(ExperimentCloneRequest experimentCloneRequest) {
        return ChangeLogExecutor.executeWithChangeLog(
                () -> commandBus.syncRun(ExperimentCloneCommand.class, experimentCloneRequest),
                experimentRunResultResponse -> {
                    if (experimentRunResultResponse.isSuccess()) {
                        trackers.trackExperimentOperation(ChangeActionType.ADD, ChangeOperatorType.USER,
                                experimentCloneRequest.getUser(),
                                experimentRunResultResponse.getResult(), null);
                    }
                });
    }

    /**
     * 删除演练
     *
     * @param experimentDeleteRequest 删除演练的请求
     * @return 删除结果
     */
    @Override
    public Response<Void> deleteExperiment(ExperimentDeleteRequest experimentDeleteRequest) {
        return ChangeLogExecutor.executeWithChangeLog(
                () -> commandBus.syncRun(ExperimentDeleteCommand.class, experimentDeleteRequest),
                experimentRunResultResponse -> {
                    if (experimentRunResultResponse.isSuccess()) {
                        trackers.trackExperimentOperation(ChangeActionType.DELETE, ChangeOperatorType.USER,
                                experimentDeleteRequest.getUser(),
                                experimentDeleteRequest.getExperimentId(), null);
                    }
                });
    }

    /**
     * 更新演练定义
     *
     * @param flowDefinitionCreateRequest 更新演练定义的请求
     * @return 更新结果
     */
    @Override
    public Response<Void> updateExperimentDefinition(ExperimentDefinitionRequest flowDefinitionCreateRequest) {
        return ChangeLogExecutor.executeWithChangeLog(
                () -> commandBus.syncRun(ExperimentDefinitionUpdateCommand.class, flowDefinitionCreateRequest),
                experimentRunResultResponse -> {
                    if (experimentRunResultResponse.isSuccess()) {
                        trackers.trackExperimentOperation(ChangeActionType.Update, ChangeOperatorType.USER,
                                flowDefinitionCreateRequest.getUser(),
                                flowDefinitionCreateRequest.getExperimentId(), null);
                    }
                });
    }

    /**
     * 根据小程序code初始化流程
     *
     * @param initMiniFlowRequest 初始化流程的请求
     * @return 初始化结果
     */
    @Override
    public Response<Map<String, List<ExperimentActivityInfo>>> initMiniFlowByAppCode(
            InitMiniFlowRequest initMiniFlowRequest) {
        return commandBus.syncRun(InitMiniFlowByAppCodeCommand.class, initMiniFlowRequest);
    }

    /**
     * openApi使用，更新演练内容
     * 根据入参，判断并更新演练基本信息、演练定义或者全部更新
     *
     * @param updateRequest 更新演练的请求
     * @return 更新结果
     */
    @Override
    public Response<Boolean> updateExperimentForOpenApi(ExperimentUpdateRequest updateRequest) {
        return commandBus.syncRun(ExperimentUpdateForOpenApiCommand.class, updateRequest);
    }

    /**
     * 预校验目标机器环境
     *
     * @param user                 用户信息
     * @param experimentRunRequest 运行演练的请求
     * @return 预校验结果
     * @throws ChaosException 异常信息
     */
    @Override
    public Response<ExperimentRunResult> preCheckExperiment(ChaosUser user, ExperimentRunRequest experimentRunRequest)
            throws ChaosException {
        return commandBus.syncRun(ExperimentExecutionCommand.class, experimentRunRequest);
    }

    /**
     * 根据appCode初始化
     *
     * @param initMiniFlowRequest 初始化流程的请求
     * @return 初始化结果
     */
    @Override
    public Response<ExperimentInit> initExperimentByAppCode(InitMiniFlowRequest initMiniFlowRequest) {
        commandBus.syncRun(InitMiniFlowByAppCodeCommand.class, initMiniFlowRequest);
        return null;
    }

    /**
     * 更新演练机器
     *
     * @param experimentHostUpdateRequest 更新演练机器的请求
     * @return 更新结果
     * @throws ChaosException 异常信息
     */
    @Override
    public Response<Boolean> updateExperimentHost(ExperimentHostUpdateRequest experimentHostUpdateRequest) throws ChaosException {
        return commandBus.syncRun(ExperimentUpdateHostCommand.class, experimentHostUpdateRequest);
    }
}
